import time
from threading import *
import random
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer, QCoreApplication
import os
import inspect
import ctypes


def reader(i):
    '''''读者进程'''
    global Rcount, a, read_wait, readResult, file
    read_wait.append(str(i))
    print('reader' + str(i) + ' waiting to read\n', end='')
    file.write('reader' + str(i) + ' waiting to read\n')
    Bmutex_1.acquire()
    ready_read_wait.append(str(i))

    Rmutex.acquire()
    if Rcount == 0:
        File.acquire()
    Rcount += 1
    Rmutex.release()

    read_wait.remove(str(i))
    ready_read_wait.remove(str(i))
    print('reader' + str(i) + ' reading\n', end='')
    file.write('reader' + str(i) + ' reading\n')
    result = a.ReadBuffer()
    readResult.append('reader' + str(i) + ': ' + result + '. ')
    time.sleep(3)
    # time.sleep(1)
    print('result:' + result + ' reader' + str(i) + ' finish read\n', end='')
    file.write('result:' + result + ' reader' + str(i) + ' finish read\n')
    Bmutex_2.release()
    Rmutex.acquire()
    Rcount -= 1
    if Rcount == 0:
        File.release()
    Rmutex.release()


def writer(i, j):
    '''''写者进程'''
    global Wcount, a, write_wait, file
    write_wait.append(str(i))
    print('writer' + str(i) + ' waiting to write\n', end='')
    file.write('writer' + str(i) + ' waiting to write\n')
    Bmutex_2.acquire()
    ready_write_wait.append((str(i), 1))

    File.acquire()
    write_wait.remove(str(i))
    print('writer' + str(i) + ' writing\n', end='')
    file.write('writer' + str(i) + ' writing\n')
    a.WriteBuffer(j)
    # time.sleep(1)
    time.sleep(3)
    ready_write_wait.remove((str(i), 1))
    print('writer' + str(i) + ' finish write', end='')
    print(a.Content)
    file.write('writer' + str(i) + ' finish write' + str(a.Content) + '\n')
    Bmutex_1.release()
    File.release()



class MyThread(Thread):
    '''''自定义线程类，可以实现线程命名、返回运行结果以及线程终止'''

    def __init__(self, func, args, name=''):
        Thread.__init__(self)
        self.func = func
        self.name = name
        self.args = args

    def run(self):
        '''''自定义线程运行方法'''
        self.res = self.func(*self.args)

    def getResult(self):
        '''''返回结果'''
        return self.res

    def _async_raise(self, tid, exctype):
        '''''系统调用，作为结束线程的具体操作'''
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")
        elif res != 1:
            # """if it returns a number greater than one, you're in trouble,
            # and you should call it again with exc=NULL to revert the effect"""
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")

    def stop_thread(self):
        '''''结束线程'''
        self._async_raise(self.ident, SystemExit)


class buffer():
    '''''自定义buffer类'''

    def __init__(self, MaxSize):
        '''''构造方法'''
        self.MaxSize = MaxSize
        self.BufferNum = 0
        self.Content = []

    def ReadBuffer(self):
        '''''读取buffer'''
        if self.BufferNum == 0:
            return 0
        else:
            i = self.Content.pop()
            self.BufferNum -= 1
            return i

    def WriteBuffer(self, i):
        '''''将i写入buffer'''
        if self.BufferNum == self.MaxSize:
            return 0
        else:
            self.Content.append(i)
            self.BufferNum += 1
            return 1


class Dialog(QtWidgets.QDialog):
    '''''重写Dialog类，实现一些额外功能'''

    def closeEvent(self, event):
        '''''重写closeEvent方法，实现dialog窗体关闭时关闭所有进程'''
        global threads
        for item in threads:
            item.stop_thread()
            print(item.name + ' is stop\n', end='')
            file.write(item.name + ' is stop\n')
        threads = []
        event.accept()


class Ui_Dialog():
    '''''窗体类，用于实现图像化界面'''

    def setupUi(self, Dialog):
        '''''初始化UI类'''
        Dialog.setObjectName("20181314骆涧松实验一")
        Dialog.resize(416, 319)
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(230, 10, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(Dialog)
        self.pushButton_2.setGeometry(QtCore.QRect(320, 10, 75, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_3 = QtWidgets.QPushButton(Dialog)
        self.pushButton_3.setGeometry(QtCore.QRect(320, 170, 75, 23))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(Dialog)
        self.pushButton_4.setGeometry(QtCore.QRect(230, 170, 75, 23))
        self.pushButton_4.setObjectName("pushButton_4")
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(20, 20, 71, 16))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Dialog)
        self.label_2.setGeometry(QtCore.QRect(20, 170, 71, 16))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(Dialog)
        self.label_3.setGeometry(QtCore.QRect(20, 50, 391, 16))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Dialog)
        self.label_4.setGeometry(QtCore.QRect(20, 80, 201, 16))
        self.label_4.setObjectName("label_4")
        self.label_6 = QtWidgets.QLabel(Dialog)
        self.label_6.setGeometry(QtCore.QRect(20, 200, 211, 16))
        self.label_6.setObjectName("label_6")
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(20, 220, 371, 20))
        self.lineEdit.setObjectName("lineEdit")
        self.textBrowser = QtWidgets.QTextBrowser(Dialog)
        self.textBrowser.setGeometry(QtCore.QRect(20, 100, 371, 61))
        self.textBrowser.setObjectName("textBrowser")
        self.pushButton_5 = QtWidgets.QPushButton(Dialog)
        self.pushButton_5.setGeometry(QtCore.QRect(20, 280, 75, 23))
        self.pushButton_5.setObjectName("pushButton_5")
        self.label_5 = QtWidgets.QLabel(Dialog)
        self.label_5.setGeometry(QtCore.QRect(20, 250, 371, 16))
        self.label_5.setObjectName("label_5")
        self.label_7 = QtWidgets.QLabel(Dialog)
        self.label_7.setGeometry(QtCore.QRect(110, 280, 261, 16))
        self.label_7.setObjectName("label_7")
        self.retranslateUi(Dialog)
        self.timer = QTimer()
        self.timer.start(10)
        QtCore.QMetaObject.connectSlotsByName(Dialog)
        self.pushButton.clicked.connect(lambda: self.addReader())
        self.pushButton_4.clicked.connect(lambda: self.addWriter(self.lineEdit))
        self.pushButton_2.clicked.connect(lambda: self.delReader())
        self.pushButton_3.clicked.connect(lambda: self.delWriter())
        self.timer.timeout.connect(lambda: self.Go(self.label_3, self.label_5, self.label_7, self.textBrowser))
        self.pushButton_5.clicked.connect(Dialog.close)

    def retranslateUi(self, Dialog):
        '''''设置一些控件的初值'''
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "20181314骆涧松实验一"))
        self.pushButton.setText(_translate("Dialog", "开始读"))
        self.pushButton_2.setText(_translate("Dialog", "结束读"))
        self.pushButton_3.setText(_translate("Dialog", "结束写"))
        self.pushButton_4.setText(_translate("Dialog", "开始写"))
        self.label.setText(_translate("Dialog", "1.读者："))
        self.label_2.setText(_translate("Dialog", "2.写者："))
        self.label_3.setText(_translate("Dialog", "读者队列等待："))
        self.label_4.setText(_translate("Dialog", "读出的内容："))
        self.label_6.setText(_translate("Dialog", "写出的内容："))
        self.pushButton_5.setText(_translate("Dialog", "结束"))
        self.label_5.setText(_translate("Dialog", "写者等待队列："))
        self.label_7.setText(_translate("Dialog", "Buffer："))

    def addReader(self):
        '''''添加一个读者'''
        global rindex, threads, k
        _translate = QtCore.QCoreApplication.translate
        t = MyThread(reader, (rindex,), 'reader' + str(rindex))
        threads.append(t)
        rindex += 1
        t.start()

    def addWriter(self, lineEdit):
        '''''添加一个写者'''
        global windex, threads
        _translate = QtCore.QCoreApplication.translate
        j = lineEdit.displayText()
        t = MyThread(writer, (windex, str(j)), 'writer' + str(windex))
        threads.append(t)
        windex += 1
        t.start()

    def Go(self, lab1, lab2, lab3, tB):
        '''''更新需要刷新的内容'''
        lab1.setText("读者队列等待：" + ' '.join(read_wait))
        lab2.setText("写者队列等待：" + ' '.join(write_wait))
        lab3.setText("Buffer：" + ' '.join(a.Content))
        tB.setText(' '.join(readResult))

    def delReader(self):
        '''''删除读者'''
        global read_wait, threads, file, Bmutex_1, ready_read_wait
        sign = 0
        if read_wait.__len__() == 0:
            return
        i = read_wait.pop()
        for j in ready_read_wait:
            if j == i:
                sign = 1
                ready_read_wait.remove(i)
                break
        for item in threads:
            if item.name == 'reader' + str(i):
                if sign == 1:
                    Bmutex_1.release()
                item.stop_thread()
                print('reader' + str(i) + ' is stop\n', end='')
                file.write('reader' + str(i) + ' is stop\n')
                threads.remove(item)
                break

    def delWriter(self):
        '''''删除写者'''
        global write_wait, threads, file, Bmutex_2, ready_write_wait
        sign = 0
        if write_wait.__len__() == 0:
            return
        i = write_wait.pop()
        for j in ready_write_wait:
            if j == i:
                sign = 1
                ready_write_wait.remove(i)
                break
        for item in threads:
            if item.name == 'writer' + str(i):
                if sign == 1:
                    Bmutex_2.release()
                item.stop_thread()
                print('writer' + str(i) + ' is stop\n', end='')
                file.write('writer' + str(i) + ' is stop\n')
                threads.remove(item)
                break


'''''程序从这里开始运行'''
a = buffer(10)
Bmutex_1 = Semaphore(a.MaxSize)
Bmutex_2 = Semaphore(a.MaxSize)
for i in range(a.MaxSize):
    Bmutex_1.acquire()
Rcount = 0
Rmutex = Semaphore(1)
File = Semaphore(1)
Wirte = Semaphore(1)
file = open('log.txt', 'w')
read_wait = []
write_wait = []
ready_read_wait = []
ready_write_wait = []
readResult = []
threads = []
rindex = 1
windex = 1
app = QtWidgets.QApplication(sys.argv)
MainWindow = Dialog()
ui = Ui_Dialog()
ui.setupUi(MainWindow)
MainWindow.show()
app.exec_()
for i in threads:
    i.join()
file.close()
os._exit(os.system('pause'))
